/*
 * ConceptTypeBuilder.java
 *
 * Created on 10 April 2007, 15:15
 *
 *
 */

package rxtokenizer;

import java.util.*;
import java.util.regex.*;
import java.io.*;
        
/**
 * Class for creating, modification and deleting concept types
 * @author Ruslan Fayzrakhmanov
 */
public class ConceptTypeBuilder {

    public ConceptTypeBuilder() {
	this.conceptTypes = new ConceptTypeContainer();
    }

	/**
	 * Creating concept type
	 * @param conceptType ConceptTypeStruct as basis for creating concept type
	 * @return Result
	 */
    public Result addConceptType(ConceptTypeStruct conceptType) {
	if (conceptType.conceptTypeId != ConceptTypeConst.REG_EXP_CONCEPT_TYPE) {
System.out.println(conceptType.conceptTypeId);
	    return Result.ERROR_02;
	}
	else {
	    if (conceptTypes.getConceptTypeByName(conceptType.name)!=null)
		return Result.ERROR_01;
	    if ( !ConceptType.isNameCorrect(conceptType.name) )
		return Result.ERROR_04;
	    RegExpConceptType regExpConceptType = new RegExpConceptType(conceptType.name, conceptType.originalExtractingExp, conceptType.constraintExtractingExp, conceptType.description);
	    Result result = regExpConceptType.fullCheckExtractingExp(conceptTypes, false);
	    if (result != Result.NO_ERROR) return result;
	    if (conceptType.constraintExtractingExp.length() > 0) {
		result = regExpConceptType.fullCheckConstraintExp();
		if (result != Result.NO_ERROR) return result;
	    }
	    result = regExpConceptType.parseExtractingExp(conceptTypes, false);
	    if (result != Result.NO_ERROR) return result;
	    if (conceptType.constraintExtractingExp.length() > 0) {
		result = regExpConceptType.parseConstraintsExp(conceptTypes);
		if (result != Result.NO_ERROR)
		    return result;
	    }
	    conceptTypes.conceptTypes.add(regExpConceptType);
	    return result;
	}
    }

    public Result addConceptType(File aFile) throws IOException {
    	BufferedReader input =  new BufferedReader(new FileReader(aFile));
    	
    	ConceptTypeStruct conceptType = new ConceptTypeStruct();
    	String line = null;
    	Result res = Result.NO_ERROR;
    	boolean isReady = false;
    	
    	while (( line = input.readLine()) != null){
    		line = line.trim();
    		if (line.length() == 0) {
    			if (isReady) {
    				isReady = false;
    				res = addConceptType(conceptType);
    				if (res!=Result.NO_ERROR) {
                                    input.close();
                                    return res;
                                }
    				conceptType.name = "";
    				conceptType.conceptTypeId = -1;
    				conceptType.constraintExtractingExp = "";
    				conceptType.description = "";
    				conceptType.originalExtractingExp = "";
    				line = "";
    			}
    		}
    		else {
    			readConceptTypeParam(line, conceptType);
    			isReady = true;
    		}
          }
    	
    	if (isReady) {
    		res = addConceptType(conceptType);
			if (res!=Result.NO_ERROR) {
                            input.close();
                            return res;
                        }
    	}
    	input.close();
    	return Result.NO_ERROR; 
    }
    
    private void readConceptTypeParam(String str, ConceptTypeStruct conceptType) {
    	int pos = str.indexOf(":");
    	if (pos <= 0) return;
    	
    	String cTParamName = str.substring(0, pos);
    	cTParamName = cTParamName.trim().toLowerCase();
    	if (cTParamName.length() == 0) return;
    	
    	String cTParamVal = str.substring(pos+1, str.length());
    	cTParamVal = cTParamVal.trim();
    	
    	if (cTParamName.equals("name")) conceptType.name = cTParamVal;
    	else if (cTParamName.equals("extractingexp")) conceptType.originalExtractingExp = cTParamVal;
    	else if (cTParamName.equals("constrextractingexp")) conceptType.constraintExtractingExp = cTParamVal;
    	else if (cTParamName.equals("concepttype")) {
    		if (cTParamVal.equalsIgnoreCase(ConceptTypeConst.REG_EXP_CONCEPT_TYPE_NAME)) {
    			conceptType.conceptTypeId = ConceptTypeConst.REG_EXP_CONCEPT_TYPE;
    		}	
    	}
    	else if (cTParamName.equals("description")) conceptType.description = cTParamVal;
    }
    
    //TODO: Works wrong.
	/**
	 * Changing existing concept type
	 * @param newConceptType Structure for creating concept type
	 * @param oldConceptType Changed concept type (link)
	 * @return Result
	 */
    public Result changeConceptType(ConceptTypeStruct newConceptType, ConceptType oldConceptType) {
	Result result = Result.NO_ERROR;
	// 1. Check instance of newConceptType
	if (newConceptType.conceptTypeId != ConceptTypeConst.REG_EXP_CONCEPT_TYPE)
	    return Result.ERROR_02;
	else {
	    int oldConceptTypeType = -1;
	    RegExpConceptType regExpConceptType;
	    if (oldConceptType instanceof RegExpConceptType) {
		oldConceptTypeType = ConceptTypeConst.REG_EXP_CONCEPT_TYPE;
		regExpConceptType = (RegExpConceptType)oldConceptType;
	    }
	    else
		return Result.ERROR_02;
	boolean nameIsChanged = ! newConceptType.name.equals(regExpConceptType.getName());
	boolean extractinExpIsChanged = ! newConceptType.originalExtractingExp.equals(regExpConceptType.getOriginalExtractingExp());
	boolean constraintExpIsChanged = ! newConceptType.constraintExtractingExp.equals(regExpConceptType.getConstraintExtractingExp());
	
	// 2. Checking newConceptType.name for unique.
	if ( nameIsChanged && (! newConceptType.name.toLowerCase().equals(regExpConceptType.name.toLowerCase())) ) {
	    if ( !ConceptType.isNameCorrect(newConceptType.name) )
		return Result.ERROR_04;
	    if (conceptTypes.getConceptTypeByName(newConceptType.name)!=null)
		return Result.ERROR_01;
	}
	if (extractinExpIsChanged) {
	    result = regExpConceptType.fullCheckExtractingExp(newConceptType.originalExtractingExp, conceptTypes, true);
	    if (result != Result.NO_ERROR)
		return result;
	}
	
	if ( (constraintExpIsChanged)&&(newConceptType.constraintExtractingExp.length() >0) ) {
	    result = regExpConceptType.fullCheckConstraintExp(newConceptType.constraintExtractingExp);
	    if (result != Result.NO_ERROR) return result;
	}
	
	if (constraintExpIsChanged) {
	    if (newConceptType.constraintExtractingExp.length() == 0) {
		regExpConceptType.deleteConstraintsExp();
	    }
	    else {
		regExpConceptType.changeConstraintExp(newConceptType.constraintExtractingExp);
		regExpConceptType.parseConstraintsExp(conceptTypes);
	    }
	    result = regExpConceptType.parseAllDerivedConceptTypes(conceptTypes);
	    if (result != Result.NO_ERROR)
		return result;
	}
	if (extractinExpIsChanged) {
	    regExpConceptType.changeExtractingExp(newConceptType.originalExtractingExp, conceptTypes);
	    result = regExpConceptType.parseExtractingExp(conceptTypes, false);
	    if (result != Result.NO_ERROR)
		return result;
	    result = regExpConceptType.parseAllDerivedConceptTypes(conceptTypes);
	    if (result != Result.NO_ERROR)
		return result;
	}
	if (nameIsChanged)
	    result = regExpConceptType.changeName(newConceptType.name);
	if (result != Result.NO_ERROR)
		return result;
	regExpConceptType.description = newConceptType.description;
	return result;
	}
    }

	/**
	 * Delete concept type by name
	 * @param name Name of concept type
	 * @return Result
	 */
    public Result deleteConceptType(String name) {
	ConceptType ct = conceptTypes.getConceptTypeByName(name);
	if (ct == null) return Result.ERROR_05;
	return deleteConceptType(ct);
    }

	/**
	 * Delete concept type
	 * @param conceptType Concept type for deleting
	 * @return Result
	 */
    public Result deleteConceptType(ConceptType conceptType) {
	Result res = conceptType.free();
	if (res != Result.NO_ERROR) return res;
	// 3. Remove conceptType from conceptTypes
	conceptTypes.conceptTypes.remove(conceptType);
	return Result.NO_ERROR;
    }

	/**
	 * 
	 */
     public ConceptTypeContainer getConceptTypes(){
        return conceptTypes;
    }

	/**
	 * 
	 * @param conceptTypes 
	 */
     public void setConceptTypes(ConceptTypeContainer conceptTypes){
        this.conceptTypes = conceptTypes;
    }

	/**
	 * List of concept types
	 */
    private ConceptTypeContainer conceptTypes = null;
    
}
